<template>
  <div class="table-animate" :style="{ '--table-bg': altStyleConfig.table.background }">
    <!-- 表头 -->
    <div
      class="table-header"
      :style="{
        '--headHeight': altStyleConfig.head.height,
        '--headBg': altStyleConfig.head.background,
        '--headColor': altStyleConfig.head.color
      }"
      v-if="!hideHeader"
    >
      <div
        :class="['header-item']"
        :style="getColumnStyle(item)"
        v-for="item in columns"
        :key="item.key"
      >
        <template v-if="item.customTitle">
          <slot :name="item.customTitle" v-bind="item"><span>{{ item.title }}</span></slot>
        </template>
        <span v-else>{{ item.title }}</span>
      </div>
    </div>
    <!-- 表格体 -->
    <div
      class="table-body"
      :style="{
        '--rowHeight': altStyleConfig.row.height,
        '--rowOddBg':
          Array.isArray(altStyleConfig.row.background)
            ? altStyleConfig.row.background[0]
            : altStyleConfig.row.background,
        '--rowEvenBg':
          Array.isArray(altStyleConfig.row.background)
            ? altStyleConfig.row.background.length === 2
              ? altStyleConfig.row.background[1]
              : altStyleConfig.row.background[0]
            : altStyleConfig.row.background,
        '--rowColor': altStyleConfig.row.color,
        '--rowGap': altStyleConfig.row.gap,
        '--focusIndex': focusIndex
      }"
    >
      <!-- 聚焦行背景 -->
      <div class="focus-line" v-if="showFocus && dataSource.length > 0"></div>
      <transition-group name="flip-list" tag="div">
        <div
          class="body-row with-focus"
          v-for="(item, index) in dataSource"
          :key="item.key"
          :style="{ '--d': index }"
        >
          <div
            :class="['row-item', { 'ellipsis': head.ellipsis }]"
            :style="getColumnStyle(head)"
            v-for="head in columns"
            :key="head.key"
          >
            <template v-if="head.customRender">
              <!-- 自定义内容 -->
              <slot :name="head.customRender" v-bind="{ text: item[head.key], record: item, index}"><span>{{ item[head.key] }}</span></slot>
            </template>
            <template v-else>
              <span>{{ item[head.key] }}</span>
            </template>
          </div>
        </div>
      </transition-group>
      <!-- 空状态 -->
      <div class="empty-wrapper" v-if="!loading && dataSource.length === 0">
        <dpro-empty :emptyText="emptyText" />
      </div>
    </div>
    <!-- 加载中 -->
    <div class="table-loading" v-show="loading">
      <dpro-loading />
    </div>
  </div>
</template>

<script>
import { DproLoading, DproEmpty } from "../../index.js";
// 组件样式默认配置
const defaultStyleConfig = {
  // 整个表格
  table: {
    background: '#020A2E'
  },
  // 表头
  head: {
    height: '36px',
    background: 'rgba(53, 125, 255, 0.15)',
    color: 'rgba(195, 248, 255, 0.9)'
  },
  // 表格行
  row: {
    height: '44px',
    // 行背景色，为数组且数组长度为2时代表[奇数行背景, 偶数行背景]，只有一个配置时表示所有行背景
    background: ['transparent', 'rgba(193, 210, 255, 0.08)'],
    color: 'rgba(255, 255, 255, 0.9)',
    gap: '0'
  }
}
export default {
  name: 'DproTableAnimate',
  props: {
    columns: {
      type: Array,
      default: () => []
    },
    dataSource: {
      type: Array,
      default: () => []
    },
    // 空状态提示文案
    emptyText: {
      type: String,
      default: '暂无数据'
    },
    loading: {
      type: Boolean,
      default: false
    },
    // 样式配置，按 defaultStyleConfig 格式配置
    styleConfig: {
      type: Object,
      default: () => {}
    },
    // 是否显示聚焦背景，轮巡切换
    showFocus: {
      type: Boolean,
      default: false
    },
    // 是否隐藏表头，默认不隐藏
    hideHeader: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      defaultStyleConfig,
      focusIndex: 0
    }
  },
  mounted() {
    if(this.showFocus) {
      this.timer = setInterval(() => {
        if(this.dataSource.length > 0) {
          let next = this.focusIndex + 1;
          this.focusIndex = next > this.dataSource.length - 1 ? 0 : next;
        }
      }, 3000);
    }
  },
  beforeDestroy() {
    this.timer && clearInterval(this.timer);
  },
  computed: {
    // 最终应用的css样式配置对象：将props自定义配置结合默认配置，并将px单位转为rem后输出配置项
    altStyleConfig() {
      let conf = {};
      console.log('computed-',this.styleConfig);
      for(let key in defaultStyleConfig) {
        conf[key] = {
          ...defaultStyleConfig[key],
          ...(this.styleConfig?.[key] || {})
        }
        // px转rem
        for(let j in conf[key]) {
          conf[key][j] = this.pxToRem(conf[key][j]);
        }
      }
      console.log('styleConfig', conf);
      return conf;
    }
  },
  components: {
    DproLoading,
    DproEmpty
  },
  methods: {
    /**
     * 根据column配置生成列的css样式表
     * @param {Object} item 表格列配置项，处理width、align等配置
     * @param {*} otherStyles 其他附加的css样式配置
     */
    getColumnStyle(item, otherStyles) {
      let width = this.getWidth(item.width);
      let style = {
        ...otherStyles,
        'text-align': ['left', 'center', 'right'].includes(item.align) ? item.align : 'left'
      }
      if(width !== undefined) {
        style = {
          ...style,
          'width': width,
          'flex': `0 0 ${width}`
        }
      } else {
        style = {
          ...style,
          'flex': `1 1 auto`,
          'width': `${100/this.columns.length}%`,
          'min-width': 0
        }
      }
      return style;
    },
    // 将表格列的width配置纯数字 转为 rem 的css属性值
    getWidth(value) {
      return typeof(value) === 'number' ? this.pxToRem(`${value}px`) : value;
    },
    /**
     * 将px单位转化为rem单位
     * @param {*} val px输入值，支持数组形式，仅转化带'px'单位的值
     * @param {*} remRootValue 转为rem的基础字体大小，卡片默认值为192
     */
    pxToRem(val, remRootValue = 192) {
      // console.log('pxToRem-input', val);
      if(Array.isArray(val)) {
        return val.map(it => this.pxToRem(it));
      }
      val = '' + val;
      // 单位不含px，直接返回
      if(val.indexOf('px') === -1) return val;
      let res = val.replace(/(\d+)px/g, function(a, b) {
        let num = b / remRootValue + '';
        return num.substring(0, 7) + 'rem';
      })
      // console.log('pxToRem-output', res);
      return res;
    }
  }
}
</script>

<style lang="less" scoped>
.table-animate {
  position: relative;
  background-color: var(--table-bg, #020A2E);
  display: flex;
  flex-direction: column;
  .table-header {
    flex: 0 0 var(--headHeight, 36px);
    width: 100%;
    display: flex;
    align-items: center;
    line-height: var(--headHeight, 36px);
    border-radius: 8px 8px 0 0;
    color: var(--headColor, rgba(195, 248, 255, 0.9));
    background: var(--headBg, rgba(53, 125, 255, 0.15));
  }
  .table-header,
  .body-row {
    padding: 0 24px;
  }
  .header-item,
  .row-item {
    font-size: 14px;
    padding: 0 16px;
    animation: fade-in-left 0.3s both;
    &.ellipsis {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
  }
  .table-body {
    flex: 1 1 auto;
    min-height: 120px;
    position: relative;
    width: 100%;
    overflow: auto;
  }
  .body-row {
    position: relative;
    width: 100%;
    min-height: var(--rowHeight, 44px);
    margin-top: var(--rowGap, 0);
    display: flex;
    align-items: center;
    &:nth-child(2n + 1) {
      background-color: var(--rowOddBg, transparent);
    }
    &:nth-child(2n) {
      background-color: var(--rowEvenBg, rgba(193, 210, 255, 0.08));
    }
  }
  .row-item {
    color: var(--rowColor, rgba(255, 255, 255, 0.9));
    animation-delay: calc(0.1s * var(--d, 0));
  }
  .focus-line {
    position: absolute;
    left: 0;
    width: 100%;
    height: var(--rowHeight, 44px);
    border-radius: calc(var(--rowHeight, 44px) / 2);
    background: #357DFF;
    animation: fade-in-left 0.3s both;
    transition: all .8s ease-in-out;
    top: calc((var(--rowGap, 0) + var(--rowHeight, 44px)) * var(--focusIndex, 0) + var(--rowGap, 0));
  }
  .table-loading {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    
  }
}
.flip-list-move {
  transition: transform .5s;
}
.empty-wrapper {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
@keyframes fade-in-left {
  0% {
    opacity: 0;
    transform: translateX(60px);
  }
  60% {
    opacity: 0.4;
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}
</style>